package com.lsq.baseadmin.modules.manage.service.impl;

import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lsq.baseadmin.common.component.DataScope;
import com.lsq.baseadmin.common.constant.ConstantSystem;
import com.lsq.baseadmin.common.enums.DataScopeEnum;
import com.lsq.baseadmin.common.enums.SwitchEnum;
import com.lsq.baseadmin.common.exception.MyException;
import com.lsq.baseadmin.common.utils.RsaEncryptUtil;
import com.lsq.baseadmin.modules.maintenance.entity.Menu;
import com.lsq.baseadmin.modules.maintenance.mapper.MenuMapper;
import com.lsq.baseadmin.modules.manage.entity.*;
import com.lsq.baseadmin.modules.manage.mapper.*;
import com.lsq.baseadmin.modules.manage.service.UserService;
import com.lsq.baseadmin.modules.manage.utils.AuthUtil;
import com.lsq.baseadmin.modules.manage.vo.AuthUser;
import com.lsq.baseadmin.modules.manage.vo.UserVo;
import com.lsq.baseadmin.modules.setting.entity.SystemSetting;
import com.lsq.baseadmin.modules.setting.mapper.SystemSettingMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 系统用户 服务实现类
 * </p>
 *
 * @author lsq
 * @since 2020-10-29
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private UserDataScopeMapper userDataScopeMapper;
    private UserRoleMapper userRoleMapper;
    private UserMenuMapper userMenuMapper;
    private MenuMapper menuMapper;
    private DepartmentMapper departmentMapper;
    private SystemSettingMapper systemSettingMapper;

    private DataScope dataScope;

    @Value("${rsa.private-key}")
    private String privateKey;

    @Override
    public UserVo login(AuthUser authUser) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("login_name", authUser.getUsername());
        User user = baseMapper.selectOne(wrapper);

        if (null == user) {
            throw new MyException(HttpStatus.UNAUTHORIZED, "用户与密码不一致！");
        }

        // 解密前端传过来的密码
        String password;
        try {
            authUser.setPassword(AuthUtil.convertPassword(authUser.getPassword()));
            password = RsaEncryptUtil.decrypt(authUser.getPassword(), privateKey);
        } catch (Exception e) {
            throw new MyException(HttpStatus.PRECONDITION_FAILED, "非法请求！");
        }

        // 解密密码跟数据库密码对比
        boolean matches = BCrypt.checkpw(password, user.getPassword());
        if (!matches) {
            throw new MyException(HttpStatus.UNAUTHORIZED, "用户与密码不一致！");
        }

        if (!user.getStatus().equals(SwitchEnum.ENABLE.getValue())) {
            throw new MyException(HttpStatus.UNAUTHORIZED, "该用户未启用，请联系管理员！");
        }

        UserVo userVo = new UserVo();
        userVo.setUser(user);
        // 获取该用户所有菜单权限
        List<Menu> menus = menuMapper.myMenus(user.getId());
        userVo.setMyMenus(menus);
        // 获取该用户数据权限
        List<UserDataScope> userDataScopes = getUserDataScopes(user);
        userVo.setUserDataScopes(userDataScopes);

        return userVo;
    }

    @Override
    public List<User> list(User user) {
        QueryWrapper<User> wrapper = createWrapper(user);
        // 测试数据权限
//                dataScope.setDataScope(wrapper);
        return baseMapper.selectList(wrapper);
    }

    @Override
    public PageInfo pg(User user, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<User> list = list(user);
        return new PageInfo<>(list);
    }

    @Override
    public UserVo detail(int id) {
        UserVo userVo = new UserVo();
        User user = baseMapper.selectById(id);
        userVo.setUser(user);

        // 获取用户拥有的角色
        QueryWrapper<UserRole> userRoleWrapper = new QueryWrapper<>();
        userRoleWrapper.eq("user_id", id);
        List<UserRole> userRoles = userRoleMapper.selectList(userRoleWrapper);
        userVo.setUserRoles(userRoles);

        // 获取用户自定义的数据权限
        if (DataScopeEnum.CUSTOMIZED.getValue().equals(user.getDataScope())) {
            List<UserDataScope> userDataScopes = getUserCustomizedDataScopes(id);
            userVo.setUserDataScopes(userDataScopes);
        }

        // 获取用户独立权限
        QueryWrapper<UserMenu> userMenuWrapper = new QueryWrapper<>();
        userMenuWrapper.eq("user_id", id);
        List<UserMenu> userMenus = userMenuMapper.selectList(userMenuWrapper);
        userVo.setUserMenus(userMenus);

        return userVo;
    }

    /**
     * 获取该用户数据权限
     * @param user 用户
     * @return  数据权限
     */
    private List<UserDataScope> getUserDataScopes(User user) {
        if (DataScopeEnum.DEPARTMENT_AND_SUB_DEPARTMENT.getValue().equals(user.getDataScope())) {
            return getUserDepartmentAndSubDepartmentDataScopes(user);
        }
        if (DataScopeEnum.CUSTOMIZED.getValue().equals(user.getDataScope())) {
            return getUserCustomizedDataScopes(user.getId());
        }
        return new ArrayList<>();
    }
    /**
     * 获取该用户的自定义数据权限
     * @param userId 用户id
     * @return  数据权限
     */
    private List<UserDataScope> getUserCustomizedDataScopes(int userId) {
        QueryWrapper<UserDataScope> userDataScopeWrapper = new QueryWrapper<>();
        userDataScopeWrapper.eq("user_id", userId);
        return userDataScopeMapper.selectList(userDataScopeWrapper);
    }

    /**
     * 获取用户本部门及子部门的数据权限
     * @param user User
     * @return 数据权限
     */
    private List<UserDataScope> getUserDepartmentAndSubDepartmentDataScopes(User user) {
        List<UserDataScope> list = new ArrayList<>();
        // 将本部门也加进去
        UserDataScope scope = new UserDataScope();
        scope.setDepartmentId(user.getDepartmentId());
        list.add(scope);

        QueryWrapper<Department> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id", user.getDepartmentId());
        List<Department> departments = departmentMapper.selectList(wrapper);

        if (departments == null || departments.size() < 1) {
            return list;
        }
        for (Department d : departments) {
            UserDataScope s = new UserDataScope();
            s.setDepartmentId(d.getId());
            list.add(s);
        }

        return list;
    }

    @Transactional(rollbackFor=RuntimeException.class)
    @Override
    public void add(UserVo userVo) {
        User user = userVo.getUser();

        // 检查用户名是否存在
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("login_name", user.getLoginName());
        int count = baseMapper.selectCount(wrapper);
        if (count > 0) {
            throw new MyException(HttpStatus.PRECONDITION_FAILED, "已存在的用户名!");
        }

        // 获取初始密码
        String initPassword = ConstantSystem.LOGIN_PASSWORD_INIT;
        QueryWrapper<SystemSetting> settingWrapper = new QueryWrapper<>();
        settingWrapper.select("init_password");
        SystemSetting systemSetting = systemSettingMapper.selectOne(settingWrapper);
        if (systemSetting != null) {
            initPassword = systemSetting.getInitPassword();
        }

        String newPassword = BCrypt.hashpw(initPassword, BCrypt.gensalt());
        user.setPassword(newPassword);

        try {
            baseMapper.insert(user);
        } catch (Exception e) {
            //如果抛出的异常是重复索引的类型
            if (e instanceof DuplicateKeyException) {
                throw new MyException(HttpStatus.PRECONDITION_FAILED, "已存在的用户名!");
            }
            throw e;
        }

        // 角色
        if (userVo.getUserRoles().size() > 0) {
            for (UserRole entry: userVo.getUserRoles()) {
                entry.setUserId(user.getId());
                userRoleMapper.insert(entry);
            }
        }

        // 数据范围
        if (DataScopeEnum.CUSTOMIZED.getValue().equals(user.getDataScope()) && userVo.getUserDataScopes().size() > 0) {
            for (UserDataScope uds: userVo.getUserDataScopes()) {
                uds.setUserId(user.getId());
                userDataScopeMapper.insert(uds);
            }
        }

        // 独立权限
        if (userVo.getUserMenus() != null && userVo.getUserMenus().size() > 0) {
            for (UserMenu userMenu : userVo.getUserMenus()) {
                userMenu.setUserId(user.getId());
                userMenuMapper.insert(userMenu);
            }
        }
    }
    @Transactional(rollbackFor=RuntimeException.class)
    @Override
    public void update(UserVo userVo) {
        User user = userVo.getUser();
        user.setLoginName(null);
        user.setPassword(null);
        baseMapper.updateById(user);

        // 角色
        QueryWrapper<UserRole> userRoleWrapper = new QueryWrapper<>();
        userRoleWrapper.eq("user_id", user.getId());
        userRoleMapper.delete(userRoleWrapper);
        if (userVo.getUserRoles().size() > 0) {
            for (UserRole entry: userVo.getUserRoles()) {
                entry.setUserId(user.getId());
                userRoleMapper.insert(entry);
            }
        }

        // 数据范围
        QueryWrapper<UserDataScope> userDataScopeWrapper = new QueryWrapper<>();
        userDataScopeWrapper.eq("user_id", user.getId());
        userDataScopeMapper.delete(userDataScopeWrapper);
        if (DataScopeEnum.CUSTOMIZED.getValue().equals(user.getDataScope()) && !userVo.getUserDataScopes().isEmpty()) {
            for (UserDataScope uds: userVo.getUserDataScopes()) {
                uds.setUserId(user.getId());
                userDataScopeMapper.insert(uds);
            }
        }

        // 独立权限
        QueryWrapper<UserMenu> userMenuWrapper = new QueryWrapper<>();
        userMenuWrapper.eq("user_id", user.getId());
        userMenuMapper.delete(userMenuWrapper);
        if (userVo.getUserMenus() != null && userVo.getUserMenus().size() > 0) {
            for (UserMenu userMenu : userVo.getUserMenus()) {
                userMenu.setUserId(user.getId());
                userMenuMapper.insert(userMenu);
            }
        }
    }

    private QueryWrapper<User> createWrapper(User user) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if(null == user) {
            return wrapper;
        }

        if(StringUtils.hasText(user.getNickName())) {
            wrapper.like("nick_name", user.getNickName());
        }

        if(user.getDepartmentId() != null) {
            wrapper.eq("department_id", user.getDepartmentId());
        }

        if(user.getStatus() != null) {
            wrapper.eq("status", user.getStatus());
        }

        if(StringUtils.hasText(user.getPhone())) {
            wrapper.like("phone", user.getPhone());
        }

        return wrapper;
    }

    @Resource
    public void setSystemSettingMapper(SystemSettingMapper systemSettingMapper) {
        this.systemSettingMapper = systemSettingMapper;
    }
    @Resource
    public void setUserMenuMapper(UserMenuMapper userMenuMapper) {
        this.userMenuMapper = userMenuMapper;
    }
    @Resource
    public void setDataScope(DataScope dataScope) {
        this.dataScope = dataScope;
    }
    @Resource
    public void setDepartmentMapper(DepartmentMapper departmentMapper) {
        this.departmentMapper = departmentMapper;
    }
    @Resource
    public void setUserRoleMapper(UserRoleMapper userRoleMapper) {
        this.userRoleMapper = userRoleMapper;
    }
    @Resource
    public void setUserDataScopeMapper(UserDataScopeMapper userDataScopeMapper) {
        this.userDataScopeMapper = userDataScopeMapper;
    }
    @Resource
    public void setMenuMapper(MenuMapper menuMapper) {
        this.menuMapper = menuMapper;
    }
}
